﻿using NineSeas.Models;
using NineSeas.ViewModels;
using Orchard;
using Orchard.ContentManagement;
using Orchard.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace NineSeas.Services
{
    public class ChapterService: IChapterService
    {
        private readonly IOrchardServices _orchardServices;

        public ChapterService(IOrchardServices orchardServices)
        {
            this._orchardServices = orchardServices;

        }
        
        public dynamic GetToc(int bookId, PaginationInfo paging)
        {
            return GetToc(bookId, paging, VersionOptions.Published);
        }

        public dynamic GetToc(int bookId, PaginationInfo paging, VersionOptions options)
        {
            Expression<Func<ChapterPartRecord, bool>> predicate = c => c.BookId == bookId;
            paging.TotalRecords = _orchardServices.ContentManager.Query<ChapterPart, ChapterPartRecord>()
                    .ForVersion(options)
                    .Where(predicate)
                    .Count();
            return _orchardServices.ContentManager.Query<ChapterPart, ChapterPartRecord>()
                    .ForVersion(options)
                    .Where(predicate)
                    .OrderBy(c => c.SortOrder)
                    .Slice(paging.StartIndex, paging.PageSize.Value)
                    .Select(c => new ChapterViewModel
                    {
                        Id = c.Id,
                        Title = c.Title,
                        SortOrder = c.SortOrder.HasValue ? c.SortOrder.Value : 0
                    });
        }
        public IList<ChapterPart> GetByBookId(int bookId)
        {
            return GetByBookId(bookId, VersionOptions.Published);
        }

        public IList<ChapterPart> GetByBookId(int bookId, PaginationInfo paging)
        {
            return GetByBookId(bookId, paging, VersionOptions.Published);   
        }


        public IList<ChapterPart> GetByBookId(int bookId, VersionOptions options)
        {
            Expression<Func<ChapterPartRecord, bool>> predicate = c => c.BookId == bookId;
            return _orchardServices.ContentManager.Query<ChapterPart, ChapterPartRecord>()
                    .ForVersion(options)
                    .Where(predicate).List().ToList();
        }

        public IList<ChapterPart> GetByBookId(int bookId, PaginationInfo paging, VersionOptions options)
        {
            Expression<Func<ChapterPartRecord, bool>> predicate = c => c.BookId == bookId;
            paging.TotalRecords = _orchardServices.ContentManager.Query<ChapterPart, ChapterPartRecord>()
                    .ForVersion(options)
                    .Where(predicate)
                    .Count();

            return _orchardServices.ContentManager.Query<ChapterPart, ChapterPartRecord>()
                    .ForVersion(options)
                    .Where(predicate)
                    .OrderBy(c => c.SortOrder)
                    .Slice(paging.StartIndex, paging.PageSize.Value)
                    .ToList();
        }

        public Models.ChapterPart Get(int id)
        {
            return Get(id, VersionOptions.Published);
        }
        public Models.ChapterPart Get(int id, VersionOptions options)
        {
            return _orchardServices.ContentManager.Get<ChapterPart>(id, options);
        }
        
        public ChapterPart GetNext(ChapterPart current)
        {
            return GetNext(current, VersionOptions.Published);
        }

        public ChapterPart GetNext(ChapterPart current, VersionOptions options)
        {
            return _orchardServices.ContentManager.Query<ChapterPart, ChapterPartRecord>()
                    .ForVersion(options)
                    .Where(c => c.BookId == current.BookId && c.SortOrder > current.SortOrder)
                    .OrderBy(c => c.SortOrder)
                    .Slice(0, 1)
                    .FirstOrDefault();
        }

        public ChapterPart GetPrevious(ChapterPart current)
        {
            return GetPrevious(current, VersionOptions.Published);
        }

        public ChapterPart GetPrevious(ChapterPart current, VersionOptions options)
        {
            return _orchardServices.ContentManager.Query<ChapterPart, ChapterPartRecord>()
                    .ForVersion(options)
                    .Where(c => c.BookId == current.BookId && c.SortOrder < current.SortOrder)
                    .OrderByDescending(c => c.SortOrder)
                    .Slice(0, 1)
                    .FirstOrDefault();
        }

        public ChapterPart GetFirst(int bookId)
        {
            return GetFirst(bookId, VersionOptions.Published);
        }

        public ChapterPart GetFirst(int bookId, VersionOptions options)
        {
            return _orchardServices.ContentManager.Query<ChapterPart, ChapterPartRecord>()
                    .ForVersion(options)
                    .Where(c => c.BookId == bookId)
                    .OrderBy(c => c.SortOrder)
                    .Slice(0, 1)
                    .FirstOrDefault();
        }

        public ChapterPart GetLast(int bookId)
        {
            return GetLast(bookId, VersionOptions.Published);
        }

        public ChapterPart GetLast(int bookId, VersionOptions options)
        {
            return _orchardServices.ContentManager.Query<ChapterPart, ChapterPartRecord>()
                    .ForVersion(options)
                    .Where(c => c.BookId == bookId)
                    .OrderByDescending(c => c.SortOrder)
                    .Slice(0, 1)
                    .FirstOrDefault();
        }

        public int? GetLastOrder(int bookId)
        {
            return GetLastOrder(bookId, VersionOptions.Published);
        }

        public int? GetLastOrder(int bookId, VersionOptions options)
        {
            return _orchardServices.ContentManager.Query<ChapterPart, ChapterPartRecord>()
                    .ForVersion(options)
                    .Where(c => c.BookId == bookId)
                    .OrderByDescending(c => c.SortOrder)
                    .Slice(0, 1)
                    .Select(c => c.SortOrder)
                    .FirstOrDefault();
        }

        public ChapterViewModel GetView(int bookId, int? order)
        {
            return GetView(bookId, order, VersionOptions.Published);
        }
        public ChapterViewModel GetView(int bookId, int? order, VersionOptions options)
        {
            ChapterViewModel result = _orchardServices.ContentManager.Query<ChapterPart, ChapterPartRecord>()
                    .ForVersion(options)
                    .Where(c => c.BookId == bookId && (order == null || c.SortOrder == order))
                    .OrderBy(c => c.SortOrder)
                    .Slice(0, 1)
                    .Select(c => new ChapterViewModel()
                    {
                        Id = c.Id,
                        Title = c.Title,
                        Content = c.Content,
                        SortOrder = c.SortOrder.HasValue ? c.SortOrder.Value : 0
                    })
                    .FirstOrDefault();

            if (result != null)
            {
                result.Previous = _orchardServices.ContentManager.Query<ChapterPart, ChapterPartRecord>()
                    .ForVersion(options)
                    .Where(c => c.BookId == bookId && c.SortOrder < result.SortOrder)
                    .OrderByDescending(c => c.SortOrder)
                    .Slice(0, 1)
                    .Select(c => c.SortOrder)
                    .FirstOrDefault();
                result.Next = _orchardServices.ContentManager.Query<ChapterPart, ChapterPartRecord>()
                    .ForVersion(options)
                    .Where(c => c.BookId == bookId && c.SortOrder > result.SortOrder)
                    .OrderBy(c => c.SortOrder)
                    .Slice(0, 1)
                    .Select(c => c.SortOrder)
                    .FirstOrDefault();
            }
            return result;
        }

        public void Move(int id, bool up)
        {
            var current = Get(id);
            if (current == null) return;

            var target = up ? GetPrevious(current) : GetNext(current);

            if (target == null) return;

            // swap position
            var tmp = target.SortOrder;
            target.SortOrder = current.SortOrder;
            current.SortOrder = tmp;
        }


        public void Delete(int id)
        {
            var chapterPart = Get(id);
            Delete(chapterPart);
        }

        public void Delete(ChapterPart chapter)
        {
            if (chapter == null) return;

            _orchardServices.ContentManager.Remove(chapter.ContentItem);
        }
    }
}